package com.linq.cool.tree;


import com.linq.cool.reflect.ReflectUtils;
import com.linq.cool.tree.annotation.TreeChild;
import com.linq.cool.tree.annotation.TreeEntity;
import com.linq.cool.tree.annotation.TreeId;
import com.linq.cool.tree.annotation.TreePid;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: yqlin
 * @Date: 2020/11/20 2:57 下午
 * @Description: 树结构实体通用工具类
 * @Version: 1.0.0
 */
public final class TreeUtilV1 {
    private final static Logger logger = LoggerFactory.getLogger(TreeUtilV1.class);
    private final static Integer FIELD_SIZE = 3;
    /**
     * Map<Class<?>, String> ---> Map<[注解类型,[字段名]>
     */
    public static Map<Class<?>, String> fieldsMap = null;

    static {
        // 避免再次扩容 默认8
        fieldsMap = new HashMap<>(8);
    }


    /**
     * stream流递归写法
     *
     * @param list  所有列表
     * @param pid   父级id
     * @param clazz 元素类型
     * @param <E>   传入元素
     *
     * @return 树状结构集合
     */
    public static <E> List<E> toTreeList(List<E> list, Object pid, Class<E> clazz) {
        if (pid instanceof String || pid instanceof Integer || pid instanceof Long) {
            if (fieldsMap.size() != FIELD_SIZE) {
                // ---->时间复杂度: O(n)
                fieldsMap = getFieldsMap(clazz);
                logger.info("调用完成 getFieldsMap:\n{}", fieldsMap);
            }
            // 获取父数据集合 并且 父赋值直接子数据集合
            return CollectionUtils.size(list) > 1 ? list.stream()
                    .filter(Objects::nonNull)
                    .filter(item -> ReflectUtils.invokeGetter(item, fieldsMap.get(TreePid.class)).equals(pid))
                    // O(n^2)
                    .peek(child -> ReflectUtils.invokeSetter(child, fieldsMap.get(TreeChild.class), getChildList(ReflectUtils.invokeGetter(child, fieldsMap.get(TreeId.class)), list)))
                    .collect(Collectors.toList()) : list;
        }
        throw new RuntimeException("父级Id必须是[String,Long,Integer]其中一种");
    }

    /**
     * 获取子元素集合
     *
     * @param id   主id
     * @param list 列表集合
     * @param <E>  传入元素
     *
     * @return 树状结构集合
     */
    private static <E> List<E> getChildList(Object id, List<E> list) {
        // 子数据集合的直接子对象 并且 子数据集合 间接赋值
        return CollectionUtils.size(list) > 1 ? list.stream()
                .filter(Objects::nonNull)
                .filter(item -> ReflectUtils.invokeGetter(item, fieldsMap.get(TreePid.class)).equals(id))
                .peek(child -> ReflectUtils.invokeSetter(child, fieldsMap.get(TreeChild.class), getChildList(ReflectUtils.invokeGetter(child, fieldsMap.get(TreeId.class)), list)))
                .collect(Collectors.toList()) : list;
    }

    /**
     * 获取 Field Map
     *
     * @param clazz 类名
     *
     * @return Map<Class < ?>, String> ---> Map<[注解类型,[字段名]>
     */
    private static <E> Map<Class<?>, String> getFieldsMap(Class<E> clazz) {
        // 获取树状结构实体
        TreeEntity treeEntity = clazz.getAnnotation(TreeEntity.class);
        // 判断注解是否为空
        if (treeEntity == null) {
            throw new RuntimeException("该实体类不是树状实体");
        }
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.getAnnotation(TreeId.class) != null) {
                fieldsMap.put(TreeId.class, field.getName());
            }
            if (field.getAnnotation(TreePid.class) != null) {
                fieldsMap.put(TreePid.class, field.getName());
            }
            if (field.getAnnotation(TreeChild.class) != null) {
                fieldsMap.put(TreeChild.class, field.getName());
            }
        }
        if (fieldsMap.size() < FIELD_SIZE) {
            throw new RuntimeException("缺少(@TreeId|@TreePid|@TreeChild)其中一个注解");
        }
        return fieldsMap;
    }
}
